<template>
  <el-popover ref="input-select" v-model="showPopover" :title="'请选择'+label" :disabled="disabled" :trigger="trigger" popper-class="input-popover" placement="bottom" width="300" @show="(e)=>{treeSuffixIcon='el-icon-yrt-xiangxiajiantou1 dropdown';onInputKeyup($refs['input-select'], {keyCode: 0})}" @hide="()=>{treeSuffixIcon='el-icon-yrt-xiangxiajiantou1'}">
    <el-input slot="reference" ref="input" v-model="currentValue" :style="{width: inputWidth}" :placeholder="placeholder" :disabled="disabled" :suffix-icon="treeSuffixIcon" class="input no-bg" @focus="(event)=>{onFocus($refs['input'], currentValue, event);}" @change="(val)=>{onInputChange($refs['input-select'], val);}" @keyup.native="(e)=>{onInputKeyup($refs['input'], e);}" @keydown.native="(event)=>{onInputKeydown($refs['input'], event);}" @blur="(event)=>{onBlur($refs['input'], currentValue, event);}">
    </el-input>
    <el-scrollbar :noresize="false" :native="false" wrap-class="popover-options scrollbar-wrap">
      <slot>
        <div v-for="(item, index) in dataList" :ref="currentOption === item?'option-item':''" :key="index" :class="['select-item', {'selected': currentOption === item, 'hover': currentValue === getItemLabel(item)}]" @click="onItemClick(getItemLabel(item), item)">
          {{ getItemLabel(item) }}
        </div>
        <div v-if="!dataList.length" class="no-data">
          没有数据
        </div>
      </slot>
    </el-scrollbar>
  </el-popover>
</template>

<script>
export default {
  name: "input-select",
  props: {
    // 字段信息
    field: {
      type: Object,
      default: () => {
        return {};
      }
    },
    // 下拉框绑定值
    value: {
      type: String,
      default: null
    },
    // 字段中文名
    label: {
      type: String,
      default: null
    },
    // 候选项列表
    options: {
      type: Array,
      required: true,
      default: () => {
        return [];
      }
    },
    // 是否禁用
    disabled: {
      type: Boolean,
      default: false
    },
    // 输入框宽度
    inputWidth: {
      type: String,
      default: "100%"
    },
    // 提示内容
    placeholder: {
      type: String,
      default: null
    },
    // 配置选项
    props: {
      type: Object,
      default: () => {
        return {
          label: "label",
          value: "value"
        };
      }
    },
    // 弹出框触发事件方式
    trigger: {
      type: String,
      default: "click"
    },
    // 选中后隐藏下拉框
    clickHidden: {
      type: Boolean,
      default: true
    },
    // 加载数据前事件
    loadDataBefore: {
      type: Function,
      default: null
    }
  },
  data () {
    return {
      // TREE选择器右侧下拉框
      treeSuffixIcon: "el-icon-yrt-xiangxiajiantou1",
      // 是否显示下拉框
      isShowPopover: false,
      // 当前行
      currentOption: {},
      // 键盘按下时延时handle
      searchHandle: null,
      // 当前数据
      dataList: []
    };
  },
  computed: {
    // 当前筛选完数据
    currentValue: {
      get: function () {
        return this.value;
      },
      set: function (val) {
        this.$emit("input", val);
      }
    },
    // 当前值
    showPopover: {
      get: function () {
        return this.isShowPopover;
      },
      set: function (val) {
        this.isShowPopover = val;
      }
    }
  },
  watch: {
    // 选项传入数据改变
    options: {
      handler (val) {
        this.dataList = [];
        val.forEach(item => {
          this.$set(this.dataList, this.dataList.length, item);
        });
      },
      deep: true
    }
  },
  mounted () {
    // 初始化下拉框数据
    this.loadData(this.$refs.input, true);
  },
  methods: {
    // item单击事件
    onItemClick (val, itemData) {
      var ref = this.$refs["input-select"];
      this.currentValue = val;
      this.$emit("on-item-click", ref, val, itemData);
      if (this.clickHidden) {
        ref.doClose();
      }
    },
    // 关闭下拉框
    close () {
      var ref = this.$refs["input-select"];
      ref.doClose();
    },
    // input change事件
    onInputChange (ref, val) {
      this.$emit("on-change", ref, val);
    },
    // input change事件
    onInputKeyup (ref, e) {
      // Up key
      if (e.keyCode === 38) {
        let existIndex = this.options.findIndex(item => {
          // return item[this.props.label] === this.currentOption;
          return item === this.currentOption;
        });
        existIndex -= 1;
        if (existIndex < 0) {
          existIndex = this.options.length - 1;
        }
        const itemData = this.options.find((item, index) => {
          return index === existIndex;
        });
        this.currentOption = itemData;
        // this.currentValue = itemData[this.props.label];
        this.$emit("on-row-change", ref, this.currentValue, itemData);
        return;
      }
      // Down key
      if (e.keyCode === 40) {
        this.showPopover = true;
        let existIndex = this.options.findIndex(item => {
          // return item[this.props.label] === this.currentValue;
          return item === this.currentOption;
        });
        existIndex += 1;
        if (existIndex >= this.options.length) {
          existIndex = 0;
        }
        const itemData = this.options.find((item, index) => {
          return index === existIndex;
        });
        this.currentOption = itemData;
        // this.currentValue = itemData[this.props.label];
        this.$nextTick(() => {
          this.$emit("on-row-change", ref, this.currentValue, itemData);
        });
        return;
      }
      // Enter key
      if (e.keyCode === 13) {
        this.currentValue = this.currentOption[this.props.label];
        this.showPopover = !this.showPopover;
        this.$refs.input.select();
        this.$refs.input.focus();
        this.onItemClick(this.currentValue, this.currentOption);
        return;
      }
      // 取消请求加载数据
      if (this.searchHandle) {
        clearTimeout(this.searchHandle);
        this.searchHandle = null;
      }
      this.searchHandle = setTimeout(() => {
        this.loadData(ref, false);
        clearTimeout(this.searchHandle);
        this.searchHandle = null;
      }, 800);
      this.$emit("on-key-up", ref, this.currentValue, e, this.currentOption);
    },
    // input keydown事件
    onInputKeydown (ref, event) {
      this.$emit("on-key-down", ref, this.currentValue, event);
    },
    // 当值当前行
    setCurrentIndex (existIndex) {
      var ref = this.$refs["input"];
      const itemData = this.options.find((item, index) => {
        return index === existIndex;
      });
      if (itemData) {
        this.currentValue = itemData[this.props.label];
        this.$nextTick(() => {
          this.$emit("on-row-change", ref, this.currentValue, itemData);
        });
        // this.$refs["input-select"].doClose();
      }
    },
    // 判断是否有选中项
    getCurrrentIndex () {
      const existIndex = this.options.findIndex(item => {
        return item[this.props.label] === this.currentValue;
      });
      return existIndex;
    },
    // 获得焦点
    onFocus (ref, val, event) {
      var disabled = ref.$attrs.disabled;
      if (disabled) return;

      this.$emit("on-focus", ref, val, event);
    },
    // 失去焦点
    onBlur (ref, val, event) {
      var disabled = ref.$attrs.disabled;
      if (disabled) return;

      this.$emit("on-blur", ref, val, event);
    },
    focus () {
      this.$refs.input.focus();
    },
    select () {
      this.$refs.input.select();
    },
    // 下拉框数据项-label值
    getItemLabel (item) {
      if (typeof item === "string") {
        return item;
      } else {
        return item[this.props.label] || item[this.props.value];
      }
    },
    // 下拉框数据项-label值
    getItemValue (item) {
      if (typeof item === "string") {
        return item;
      } else {
        return item.value !== null ? item[this.props.value] : item[this.props.label];
      }
    },
    // 下拉框输入改变后加载数据
    loadData (ref, isInit) {
      if (!this.field || !this.field.options) return;

      const val = !isInit ? this.currentValue : "";
      const url = this.field.options.url;
      if (url) {
        if (!this.field.options.searchFields) {
          this.$message.error(`字段【${this.field.options.prop}】未设置查询字段！`);
          return;
        }
        const params = {
          name: val,
          searchFields: this.field.options.searchFields.split(",")
        };
        if (typeof this.loadDataBefore === "function") {
          this.loadDataBefore(params);
        }
        this.common.ajax(url, params, res => {
          this.common.showMsg(res);
          this.dataList = [];
          if (res.result) {
            res.data.forEach(item => {
              this.$set(this.dataList, this.dataList.length, item);
            });
          }
        });
      }
    }
  }
};
</script>

<style lang="scss" scoped>
.input {
  ::v-deep .el-input__icon.el-icon-yrt-xiangxiajiantou1 {
    transition: all 0.6s;
    -moz-transition: all 0.6s; /* Firefox 4 */
    -webkit-transition: all 0.6s; /* Safari and Chrome */
    -o-transition: all 0.6s; /* Opera */
    height: 36px;
    &.dropdown {
      transform: rotateZ(-180deg) translateY(3px);
      -ms-transform: rotateZ(-180deg) translateY(3px); /* Internet Explorer */
      -moz-transform: rotateZ(-180deg) translateY(3px); /* Firefox */
      -webkit-transform: rotateZ(-180deg) translateY(3px); /* Safari 和 Chrome */
      -o-transform: rotateZ(-180deg) translateY(3px); /* Opera */
    }
  }
  ::v-deep .el-input__inner {
    padding-left: 5px;
  }
}
.select-item {
  font-size: 14px;
  padding: 0 20px;
  position: relative;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: #606266;
  height: 34px;
  line-height: 34px;
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
  cursor: pointer;
  &.hover,
  &:hover {
    background-color: #f5f7fa;
  }
  &:last-child {
    margin-bottom: 20px;
  }
  &.selected {
    color: #409eff;
    font-weight: 700;
  }
}
.no-data {
  font-size: 14px;
  padding: 0 20px;
  position: relative;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: #606266;
  height: 34px;
  line-height: 34px;
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
  &:last-child {
    margin-bottom: 20px;
  }
}
.el-scrollbar {
  ::v-deep .popover-options.scrollbar-wrap {
    max-height: 200px;
    overflow-x: hidden;
    padding: 0px;
  }
}
</style>
